Skip to content

Conversation

sffc
Copy link
Collaborator

@sffc sffc commented Jul 11, 2025

See #3116

This preserves the original call to GetOption, but it always calls it with the full list of units, and I pull the subset-checking logic into a separate AO.

I have two commits: an editorial change to split the AO in two, and a small normative change to move the validation later down at the call sites.

@nekevss @Manishearth

@sffc sffc requested a review from ptomato July 11, 2025 00:50
Copy link

codecov bot commented Jul 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.86%. Comparing base (a48c297) to head (93d7c24).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3130   +/-   ##
=======================================
  Coverage   96.86%   96.86%           
=======================================
  Files          22       22           
  Lines       10081    10081           
  Branches     1824     1824           
=======================================
  Hits         9765     9765           
  Misses        267      267           
  Partials       49       49           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sffc sffc changed the title Normative: Validate Temporal-valued unit options after all options are read Normative: Validate unit-valued options after all options are read Jul 11, 2025
@sffc sffc force-pushed the validate-unit branch 2 times, most recently from 70fa5fa to b3f6a0f Compare July 11, 2025 01:09
@sffc
Copy link
Collaborator Author

sffc commented Jul 11, 2025

The code that changes behavior with this PR is something like:

obj = {
    get largestUnit() {
        console.log("get largestUnit");
        return "years";
    },
    get smallestUnit() {
        console.log("get smallestUnit");
        return "seconds";
    },
}

Temporal.PlainTime.from("00:00").round(obj)

Current behavior: console logs "get largestUnit" and then RangeError is thrown.

New behavior: console logs both "get largestUnit" and "get smallestUnit", and then RangeError is thrown.

Note: the RangeError is because PlainTime does not allow "years" as a largestUnit. There is no difference in behavior if get largestUnit() returns an invalid string such as "INVALID".

(as noted previously, there doesn't appear to be Test262 coverage for this)

Copy link
Collaborator

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intended changes as I understand them do seem both reasonable and narrow, but I think the algorithms steps fail to properly implement them.

Copy link
Contributor

@Manishearth Manishearth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is roughly what I was imagining, thanks for doing all this work!

As Richard has noted, handling unset/default values may be tricky. The way I was expecting it to work was that the get allows you to specify REQUIRED, and Validate doesn't need to care, which roughly appears to be what you're doing here.

@sffc sffc requested a review from gibson042 July 14, 2025 22:01
Copy link
Collaborator

@ptomato ptomato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised that this didn't show up in more places. But I guess smallestUnit is often the last option read anyway, because S is relatively late in the alphabet. So I'm pleasantly surprised at the small extent of the normative change. (I am assuming this PR is the full extent of the changes!)

All in all I'd still prefer not to do this. (It isn't a bug in the proposal, it sets a new precedent that TC39 hasn't really shown appetite for so far, and I just don't see the alternative workaround in temporal_rs as that big of a deal.) But it's small and targeted enough that if I'm the only opposing voice, I won't stand in the way.

Logistical note: to make the best impression when presenting to TC39, I'd recommend squashing the fixup commits into their appropriate editorial or normative commits, then splitting out the editorial commit into its own PR which I can review quickly and merge. That way, there's less for delegates to review and it's much clearer what is changing.

@sffc
Copy link
Collaborator Author

sffc commented Jul 17, 2025

This PR fixes the issues involving unit-valued options, which is the current scope of the issue and all I'm asking for at this time.

Yes, often smallestUnit is the final read, so no change was needed in those cases.

Yes, splitting the editorial change into its own PR is something I'm happy to do.

@dminor
Copy link

dminor commented Jul 18, 2025

@anba Do you have any concerns about this change?

@sffc
Copy link
Collaborator Author

sffc commented Jul 18, 2025

I opened #3135 for the editorial changes.

@ptomato
Copy link
Collaborator

ptomato commented Jul 19, 2025

The editorial changes are merged, and I rebased this. So now it's just the minimal set of normative changes.

@anba
Copy link
Contributor

anba commented Jul 21, 2025

@anba Do you have any concerns about this change?

I don't think so. It'll require some small refactoring because the current SM implementation sometimes uses AUTO as a placeholder to represent absent values. This approach is no longer possible when "auto" must always initially be parsed as a valid Temporal unit option. But apart from that I don't see any implementation issues.

(The SM implementation already parses the unit options accepting all units and only later check which units are actually allowed. )

@Jack-Works
Copy link
Member

I wonder is there a difference between "Get-Cast-Get-Cast-Validate" and "Get-Get-Cast-Cast-Validate"

@ptomato
Copy link
Collaborator

ptomato commented Aug 4, 2025

I wonder is there a difference between "Get-Cast-Get-Cast-Validate" and "Get-Get-Cast-Cast-Validate"

Yes, there is, the Get step may fail if the object has an accessor property, and the Cast step may fail if the property is of the wrong type, so it's observable.

@ptomato
Copy link
Collaborator

ptomato commented Aug 4, 2025

I'd like to write test262 tests for this before merging it, because it's not covered at all. To that end, it'd be helpful if #3142 could be reviewed and merged first, as it contains the updates to the reference code for the editorial changes.

@Jack-Works
Copy link
Member

I wonder is there a difference between "Get-Cast-Get-Cast-Validate" and "Get-Get-Cast-Cast-Validate"

Yes, there is, the Get step may fail if the object has an accessor property, and the Cast step may fail if the property is of the wrong type, so it's observable.

I'd like to know why you chose "Get-Cast-Get-Cast-Validate", not "Get-Get-Cast-Cast-Validate". Is there a difference between them when making a fast implementation? If there is no difference, "Get-Get-Cast-Cast-Validate" looks clearer to me.

@sffc
Copy link
Collaborator Author

sffc commented Aug 8, 2025

I wonder is there a difference between "Get-Cast-Get-Cast-Validate" and "Get-Get-Cast-Cast-Validate"

Yes, there is, the Get step may fail if the object has an accessor property, and the Cast step may fail if the property is of the wrong type, so it's observable.

I'd like to know why you chose "Get-Cast-Get-Cast-Validate", not "Get-Get-Cast-Cast-Validate". Is there a difference between them when making a fast implementation? If there is no difference, "Get-Get-Cast-Cast-Validate" looks clearer to me.

The thinking was that Get and Cast are both steps that deeply involve the JS bindings, a layer above the library boundary, whereas Validate is on the library layer. Also, the champions didn't want to make a large change, and Get Get Cast Cast would involve rewriting all call sites of GetOption.

@ptomato ptomato force-pushed the validate-unit branch 3 times, most recently from b226658 to f60035a Compare August 12, 2025 00:43
ptomato added a commit to ptomato/test262 that referenced this pull request Aug 15, 2025
These tests cover the normative change approved in the July 2025 TC39
plenary. See tc39/proposal-temporal#3130.
All properties of user-passed options objects should be read and cast
before any "algorithmic validation" is done.

This is a lot of tests, that cover every entry point where an options
object is passed in, where subsequently an exception can be thrown or user
code can be called.

However, the normative change only affects 10 of these tests:

- Instant.p.since,until,toString
- PlainDate.p.since,until
- PlainTime.p.since,until
- PlainYearMonth.p.since,until
- ZonedDateTime.p.toString

The other 35 tests simply close a gap in coverage.
ptomato added a commit to ptomato/test262 that referenced this pull request Aug 15, 2025
These tests cover the normative change approved in the July 2025 TC39
plenary. See tc39/proposal-temporal#3130.
All properties of user-passed options objects should be read and cast
before any "algorithmic validation" is done.

This is a lot of tests, that cover every entry point where an options
object is passed in, where subsequently an exception can be thrown or user
code can be called.

However, the normative change only affects 10 of these tests:

- Instant.p.since,until,toString
- PlainDate.p.since,until
- PlainTime.p.since,until
- PlainYearMonth.p.since,until
- ZonedDateTime.p.toString

The other 35 tests simply close a gap in coverage.
@ptomato
Copy link
Collaborator

ptomato commented Aug 15, 2025

I've written tests to cover this in tc39/test262#4557. Please check if the behaviour is as you expect.

@Manishearth
Copy link
Contributor

Is the handling of Auto correct here?

@sffc I am trying to implement this, and I noted that GetTemporalUnitValuedOption unconditionally parses "auto", however no call for Validate has auto as extraValues, AND auto is not in the table, so AIUI Validate will always reject Auto. Probably a bug?

@sffc
Copy link
Collaborator Author

sffc commented Aug 15, 2025

We think that the only case where ~auto~ is allowed is a case where everything is allowed, and so we removed the validate call entirely, in #3143

@ptomato
Copy link
Collaborator

ptomato commented Aug 15, 2025

I don't think there's a bug?
largestUnit: 'auto' is accepted in since, until, and Duration.round methods. In GetDifferenceSettings auto is given in extraValues here. In Duration.round, no call to Validate is needed because all the possible values are valid, see #3130 (comment).

@Manishearth
Copy link
Contributor

Ah! I was looking at calls to Validate, so I didn't notice there was a case without a call. Thanks!

Might make a PR to add this to the description.

@sffc
Copy link
Collaborator Author

sffc commented Aug 15, 2025

There is one other call site of validate that permits auto, in GetDifferenceSettings

@Manishearth
Copy link
Contributor

I've written tests to cover this in tc39/test262#4557. Please check if the behaviour is as you expect.

I can verify that V8 updated to this PR passes those tests

hubot pushed a commit to v8/v8 that referenced this pull request Aug 21, 2025
This updates to the non-observable changes from
tc39/proposal-temporal#3135

This also makes the changes from to-be-merged spec PR
tc39/proposal-temporal#3130

(these changes are observable)

This passes the tests added in
tc39/test262#4557.

Bug: 401065166
Change-Id: I6a6a6964a2436085a3fa20b3bbb10392f0fe95df
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6851756
Auto-Submit: Manish Goregaokar <[email protected]>
Commit-Queue: Manish Goregaokar <[email protected]>
Reviewed-by: Leszek Swirski <[email protected]>
Cr-Commit-Position: refs/heads/main@{#101978}
ptomato added a commit to ptomato/test262 that referenced this pull request Aug 21, 2025
These tests cover the normative change approved in the July 2025 TC39
plenary. See tc39/proposal-temporal#3130.
All properties of user-passed options objects should be read and cast
before any "algorithmic validation" is done.

This is a lot of tests, that cover every entry point where an options
object is passed in, where subsequently an exception can be thrown or user
code can be called.

However, the normative change only affects 10 of these tests:

- Instant.p.since,until,toString
- PlainDate.p.since,until
- PlainTime.p.since,until
- PlainYearMonth.p.since,until
- ZonedDateTime.p.toString

The other 35 tests simply close a gap in coverage.
ptomato added a commit to tc39/test262 that referenced this pull request Aug 21, 2025
These tests cover the normative change approved in the July 2025 TC39
plenary. See tc39/proposal-temporal#3130.
All properties of user-passed options objects should be read and cast
before any "algorithmic validation" is done.

This is a lot of tests, that cover every entry point where an options
object is passed in, where subsequently an exception can be thrown or user
code can be called.

However, the normative change only affects 10 of these tests:

- Instant.p.since,until,toString
- PlainDate.p.since,until
- PlainTime.p.since,until
- PlainYearMonth.p.since,until
- ZonedDateTime.p.toString

The other 35 tests simply close a gap in coverage.
@ptomato
Copy link
Collaborator

ptomato commented Aug 21, 2025

It'll be easiest if I can get a review of #3145 before merging this one, because it's convenient to pull in updated test262 commits in order.

@ptomato ptomato dismissed gibson042’s stale review August 22, 2025 19:36

Comments were addressed

@ptomato ptomato merged commit c093099 into tc39:main Aug 22, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants